package com.st.mongodb;

import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class SentiStatusCodecUseReflex implements Codec<SentiStatus> {

  @Override
  public void encode(BsonWriter writer, SentiStatus value,
                     EncoderContext encoderContext) {

    writer.writeStartDocument();
    writer.writeString("mid", value.getMid());
    writer.writeString("text", value.getText());
    writer.writeString("retText", value.getRetText());
    writer.writeEndDocument();
  }

  @Override
  public Class<SentiStatus> getEncoderClass() {
    return SentiStatus.class;
  }

  @Override
  public SentiStatus decode(BsonReader reader, DecoderContext decoderContext) {
    SentiStatus sentiStatus = new SentiStatus();

    //和放入顺序有关 必须一致 且不能有多余的字段
    reader.readStartDocument();

    Field[] fields = SentiStatus.class.getDeclaredFields();
    List<String> fieldNames = getFields(fields);

    Object value = null;
    Class type = null;
    while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
      String fieldName = reader.readName();

      if (!fieldNames.contains(fieldName))
        continue;

      switch (reader.getCurrentBsonType()) {
        case INT32: {
          value = reader.readInt32(fieldName);
          type = Integer.class;
          break;
        }
        case INT64: {
          value = reader.readInt64(fieldName);
          type = Long.class;
          break;
        }
        case DOUBLE: {
          value = reader.readDouble(fieldName);
          type = Double.class;
          break;
        }
        case STRING: {
          value = reader.readString(fieldName);
          type = String.class;
          break;
        }
      }

      setMethod(fieldName, sentiStatus, type, value);
    }

    reader.readEndDocument();

    return sentiStatus;
  }

  private List<String> getFields(Field[] fields) {
    List<String> fieldList = new ArrayList<String>();

    for (Field field : fields) {
      fieldList.add(field.getName());
    }

    return fieldList;

  }

  private void setMethod(String fieldName, SentiStatus sentiStatus, Class type, Object value) {
    String MethodName = new StringBuilder("set").append(fieldName.substring(0, 1).toUpperCase()).append(fieldName.substring(1)).toString();

    try {
      Method method = SentiStatus.class.getMethod(MethodName, type);
      method.invoke(sentiStatus, value);
    } catch (NoSuchMethodException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SecurityException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IllegalArgumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
